package ${packageName};

import cn.pink.core.gen.proxy.RPCProxyBase;
import cn.pink.core.*;
import cn.pink.common.support.tools.node.NodeTool;
import cn.pink.core.support.Param;
import cn.pink.core.support.Utils;
import cn.pink.core.support.function.*;
<#if importPackages??>
<#list importPackages as package>
import ${package};
</#list>
</#if>
import cn.pink.core.gen.IronGenFile;

${mainAnnotation}
@IronGenFile
public class RPCProxy {
	<#list methodsList as proxy>
	public static final class ${proxy.className}Proxy extends RPCProxyBase {
		public final class EnumCall{
			<#assign i = 0>
			<#list proxy.methods as method>
			<#assign i = i + 1>
			public static final int ${method.enumCall} = ${i};
			</#list>
		}

		public static final String DIST_NAME = "${proxy.className}";

		private CallPoint remote;
		private Port localPort;

		private static NodeType nodeType = NodeType.${proxy.nodeType};
		
		/**
		 * 私有构造函数
		 * 防止实例被私自创建 必须通过newInstance函数
		 */
		private ${proxy.className}Proxy() {}
	
		<#if proxy.singleton>
		/**
		 * 伪随机随机获取远程实例
		 * 优先获取本地实例
		 */
		public static ${proxy.className}Proxy newInstance() {
			NodeInfo nodeInfo = NodeTool.getInstance().getRandomNode(nodeType);
			return createInstance(nodeInfo.getNodeId(), nodeInfo.getPortId(), DIST_NAME);
		}

		public static ${proxy.className}Proxy newInstance(String nodeId, String portId) {
			return createInstance(nodeId, portId, DIST_NAME);
		}
		<#else>

        /**
		 * 获取实例
		 */
//		public static ${proxy.className}Proxy newInstance(String portId) {
//			return createInstance(nodeId, portId, DIST_NAME);
//		}

		/**
		 * 获取实例
		 */
		public static ${proxy.className}Proxy newInstance(CallPoint targetPoint) {
			return createInstance(targetPoint.nodeId, targetPoint.portId, targetPoint.servId);
		}
		
		/**
		 * 获取实例
		 */
		public static ${proxy.className}Proxy newInstance(String node, String port, Object id) {
			return createInstance(node, port, id);
		}
        </#if>

		/**
		 * 创建实例
		 */
		private static ${proxy.className}Proxy createInstance(String node, String port, Object id) {
			${proxy.className}Proxy inst = new ${proxy.className}Proxy();
			inst.localPort = Port.getCurrent();
			inst.remote = new CallPoint(node, port, id);
			
			return inst;
		}
		
		/**
		 * 监听返回值
		 */
		public void listenResult(IronFunction2<Param, Param> method, Object...context) {
			listenResult(method, new Param(context));
		}
		
		/**
		 * 监听返回值
		 */
		public void listenResult(IronFunction2<Param, Param> method, Param context) {
			context.put("_callerInfo", remote.callerInfo);
			localPort.listenResult(method, context);
		}
		
		
		public void listenResult(IronFunction3<Boolean, Param, Param> method, Object...context) {
			listenResult(method, new Param(context));
		}
		
		public void listenResult(IronFunction3<Boolean, Param, Param> method, Param context) {
			context.put("_callerInfo", remote.callerInfo);
			localPort.listenResult(method, context);
		}
		
		<#list proxy.methods as method>
		public void ${method.name}(${method.params}) {
			remote.callerInfo = Utils.getCallerInfo();
			localPort.call(remote, EnumCall.${method.enumCall}, new Object[]{ ${method.paramsCall} });
		}
		</#list>
		
		<#list proxy.methods as method>
		public Call makeCall_${method.name}(${method.params}) {
			Call call = localPort.makeCall(remote, EnumCall.${method.enumCall}, new Object[]{ ${method.paramsCall} });
			call.to.callerInfo = Utils.getCallerInfo();
			
			return call;
		}	
		</#list>
	}
	
	</#list>
}